﻿using System;
using System.Collections.Concurrent;
using RpcClient.Attr;
using RpcClient.Interface;

using RpcHelper;

using RpcModular.Config;
using RpcModular.Domain;
using RpcModular.Model;
using RpcModularModel.Identity.Msg;

namespace RpcModular.Service
{

    [ClassLifetimeAttr(ClassLifetimeType.单例)]
    internal class IdentityService : IIdentityService
    {
        private static readonly ConcurrentDictionary<string, UserIdentity> _Identity = new ConcurrentDictionary<string, UserIdentity>();
        [ThreadStatic]
        private static string _IdentityId;
        private IdentityConfig _Config = null;

        public string IdentityId
        {
            get => _IdentityId ?? this._Config.DefAppId;
            set => _IdentityId = value;
        }
        public bool IsEnableIdentity
        {
            get;
            private set;
        }
        static IdentityService()
        {
            RpcClient.RpcClient.Route.AddRoute<UpdateIdentity>(a =>
           {
               if (_Identity.TryGetValue(a.AppId.ToString("N"), out UserIdentity identity))
               {
                   identity.ResetLock();
               }
           });
            AutoClearDic.AutoClear<string, UserIdentity>(_Identity);
        }
        public IdentityService(IRpcService service)
        {
            this._Config = ModularConfig.GetIdentityConfig();
            IdentityConfig.RefreshEvent += this.IdentityConfig_RefreshEvent;
            service.SendIng += this.RpcEvent_SendEvent;
            service.ReceiveEnd += this.Service_ReceiveEnd;
        }

        private void Service_ReceiveEnd(RpcClient.Model.IMsg msg, RpcModel.TcpRemoteReply reply)
        {
            _IdentityId = null;
        }

        private void RpcEvent_SendEvent(RpcModel.IRemoteConfig config, IRemote remote, object page, int sendNum)
        {
            if (sendNum == 0 && this.IdentityId != null)
            {
                config.SetAppIdentity(page, this.IdentityId);
            }
        }

        private void IdentityConfig_RefreshEvent()
        {
            this._Config = ModularConfig.GetIdentityConfig();
            this.IsEnableIdentity = this._Config.IsEnable;
        }

        private static bool _GetIdentity(string id, out UserIdentity identity)
        {
            if (!_Identity.TryGetValue(id, out identity))
            {
                identity = _Identity.GetOrAdd(id, new UserIdentity(id));
            }
            if (!identity.Init())
            {
                _Identity.TryRemove(id, out identity);
                identity.Dispose();
                return false;
            }
            return identity.IsInit;
        }

        public IdentityDomain GetIdentity()
        {
            if (!_GetIdentity(this.IdentityId, out UserIdentity identity))
            {
                throw new ErrorException(identity.Error);
            }
            else
            {
                return new IdentityDomain(identity);
            }
        }

        public bool Check()
        {
            if (this.IdentityId != null)
            {
                return true;
            }
            else if (this._Config.IsEnable)
            {
                throw new ErrorException("identity.null");
            }
            _IdentityId = null;
            return false;
        }

        public void CheckState()
        {
            if (!_GetIdentity(this.IdentityId, out UserIdentity identity))
            {
                throw new ErrorException(identity.Error);
            }
        }
    }
}
